﻿namespace NTLib.Core.Threading
{
    using NTLib.Core.ScopeLock;
    using System;
    using System.Threading;

    /// <summary>
    /// Extensions methods use to improve the usage od the ReaderWriterLockSlim Object
    /// </summary>
    public static class ReaderWriterLockSlimExtensions
    {
        /// <summary>
        /// Locks in Read the ReaderWriterLockSlim.
        /// </summary>
        /// <param name="locker">The locker.</param>
        /// <param name="token">The token.</param>
        /// <returns>
        /// Return a scope lock item that will release the lock on dispose
        /// </returns>
        public static ScopeLockItem<ReaderWriterLockSlim> LockRead(this ReaderWriterLockSlim locker, CancellationToken token = default(CancellationToken))
        {
            try
            {
                if (locker.IsReadLockHeld)
                    return new ScopeLockItem<ReaderWriterLockSlim>(locker, (l) => { });

                 while (!locker.IsReadLockHeld && !locker.TryEnterReadLock(2))
                    token.ThrowIfCancellationRequested();
            }
            catch (ObjectDisposedException)
            {

            }
            return new ScopeLockItem<ReaderWriterLockSlim>(locker, (l) =>
            {
                try
                {
                    if (l.IsReadLockHeld)
                        l.ExitReadLock();
                }
                catch (ObjectDisposedException)
                {

                }
            });
        }

        /// <summary>
        /// Locks in Read the ReaderWriterLockSlim.
        /// </summary>
        /// <param name="locker">The locker.</param>
        /// <param name="token">The token.</param>
        /// <returns>
        /// Return a scope lock item that will release the lock on dispose
        /// </returns>
        public static ScopeLockItem<ReaderWriterLockSlim> LockUpgradeableRead(this ReaderWriterLockSlim locker, CancellationToken token = default(CancellationToken))
        {
            try
            {
                if (locker.IsUpgradeableReadLockHeld)
                    return new ScopeLockItem<ReaderWriterLockSlim>(locker, (l) => { });

                while (!locker.IsUpgradeableReadLockHeld && !locker.TryEnterUpgradeableReadLock(2))
                    token.ThrowIfCancellationRequested();
            }
            catch (ObjectDisposedException)
            {

            }

            return new ScopeLockItem<ReaderWriterLockSlim>(locker, (l) =>
            {
                try
                {
                    if (l.IsUpgradeableReadLockHeld)
                        l.ExitUpgradeableReadLock();
                }
                catch (ObjectDisposedException)
                {

                }
            });
        }

        /// <summary>
        /// Locks in write the ReaderWriterLockSlim.
        /// </summary>
        /// <param name="locker">The locker.</param>
        /// <param name="token">The token.</param>
        /// <returns>
        /// Return a scope lock item that will release the lock on dispose
        /// </returns>
        public static ScopeLockItem<ReaderWriterLockSlim> LockWrite(this ReaderWriterLockSlim locker, CancellationToken token = default(CancellationToken))
        {
            try
            {
                if (locker.IsWriteLockHeld)
                    return new ScopeLockItem<ReaderWriterLockSlim>(locker, (l) => { });

                while (!locker.IsWriteLockHeld && !locker.TryEnterWriteLock(2))
                    token.ThrowIfCancellationRequested();

            }
            catch (ObjectDisposedException)
            {

            }

            return new ScopeLockItem<ReaderWriterLockSlim>(locker, (l) =>
            {
                try
                {
                    if (l.IsWriteLockHeld)
                        l.ExitWriteLock();
                }
                catch (ObjectDisposedException)
                {

                }
            });
        }
    }
}


